package com.xinou.daily_report.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xinou.common.base.config.ApiResponse;
import com.xinou.common.base.exception.BusException;
import com.xinou.common.util.BeanUtil;
import com.xinou.daily_report.PO.daily.*;
import com.xinou.daily_report.VO.daily.DailyInfoVO;
import com.xinou.daily_report.VO.DailyListExcelVO;
import com.xinou.daily_report.VO.DailySingleListVO;
import com.xinou.daily_report.VO.DailyUserListVO;
import com.xinou.daily_report.VO.daily.DailyListVO;
import com.xinou.daily_report.VO.daily.MiniDailyListVO;
import com.xinou.daily_report.entity.*;
import com.xinou.daily_report.enumerate.SysConfigEnum;
import com.xinou.daily_report.mapper.SysDailyCommentMapper;
import com.xinou.daily_report.mapper.SysDailyMapper;
import com.xinou.daily_report.mapper.SysFlowerMapper;
import com.xinou.daily_report.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xinou.daily_report.utils.ConstUtil;
import com.xinou.daily_report.utils.DailyShiroUtil;
import com.xinou.daily_report.utils.TimeCheckUtil;
import com.xinou.sso.mapper.SysUserMapper;
import com.xinou.sso.service.SysUserService;
import com.xinou.sso.util.ShiroUtil;
import com.xinou.sso.vo.user.UserListVO;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author ${author}
 * @since 2021-06-11
 */
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class SysDailyServiceImpl extends ServiceImpl<SysDailyMapper, SysDaily> implements SysDailyService {

    final SysDailySingleService sysDailySingleService;
    final SysUserService sysUserService;
    final SysUserMapper sysUserMapper;
    final SysDailyMapper sysDailyMapper;
    final SysDailyCommentMapper sysDailyCommentService;
    final SysOkFormService sysOkFormService;
    final SysFlowerMapper sysFlowerMapper;

    @Override
    public ApiResponse<Boolean> dailyAdd(DailyAddPO po) {
    if (!TimeCheckUtil.canSubmit()) {
            throw new BusException("提交失败，不在提交时间段内!");
        }
        LocalDate now = LocalDate.now();
        if (po.getDailyTime() == null) {
            po.setDailyTime(now);
        }
        // 补缴
        Integer state;
        if (po.getDailyTime().isBefore(now)) {
            int counts = count(new LambdaQueryWrapper<SysDaily>()
                    .eq(SysDaily::getDailyTime, po.getDailyTime())
                    .eq(SysDaily::getWorkerId, ShiroUtil.getUserId())
                    .and(wq -> wq
                            .eq(SysDaily::getState, 0)
                            .or()
                            .eq(SysDaily::getState, 1)
                    )
            );
            if (counts == 1) {
                    throw new BusException("所选日期已经提交过！");
            }
            state = 1;
        }else if (po.getDailyTime().equals(now)) {
            int counts = count(new LambdaQueryWrapper<SysDaily>()
                    .eq(SysDaily::getDailyTime, po.getDailyTime())
                    .eq(SysDaily::getWorkerId, ShiroUtil.getUserId())
                    .eq(SysDaily::getState, 0)
            );
            if (counts == 1) {
                throw new BusException("所选日期已经提交过！");
            }
            state = 0;
        }else if (po.getDailyTime().isAfter(now)) {
            int counts = count(new LambdaQueryWrapper<SysDaily>()
                    .eq(SysDaily::getDailyTime, po.getDailyTime())
                    .eq(SysDaily::getWorkerId, ShiroUtil.getUserId())
                    .eq(SysDaily::getState, 2)
            );
            if (counts == 1) {
                throw new BusException("最多能添加" + ConstUtil.DAILY_PLAN_MAX_COUNT + "条未来计划");
            }
            state = 2;
        }else {
            throw new BusException("添加失败");
        }
        SysDaily sysDaily = BeanUtil.beanA2beanB(po, SysDaily.class);
        sysDaily.setInsertTime(LocalDateTime.now());
        sysDaily.setState(state);
        sysDaily.setWorkerId(ShiroUtil.getUserId());
        sysDaily.setDeptId(ShiroUtil.getUserDto().getDeptId());
        saveOrUpdate(sysDaily);
        sysDailySingleService.saveOrUpdateBatch(po.getSingleList().stream().map(k -> k.setDailyId(sysDaily.getId())).collect(Collectors.toList()));
        return new ApiResponse<>(Boolean.TRUE);
    }

    @Override
    public ApiResponse<Boolean> dailyDelete(DailyDeletePO po) {
        if (po == null || po.getId() == null) {
            throw new BusException("某条件为空!");
        }
        removeById(po.getId());
        sysDailySingleService.remove(
                new LambdaQueryWrapper<SysDailySingle>().eq(SysDailySingle::getDailyId, po.getId()
                ));
        return new ApiResponse<>(Boolean.TRUE);
    }

    @Override
    public ApiResponse<DailyListVO> dailyList(DailyListPO po) {
        Page<SysDaily> page = new Page<>(po.getPageNumber(), po.getPageSize());
        return new ApiResponse<>(this.baseMapper.dailyList(page, po));
    }

    @Override
    public ApiResponse<MiniDailyListVO> miniDailyList(DailyListPO po) {
        Page<SysDaily> page = new Page<>(po.getPageNumber(), po.getPageSize());
        DailyListPO todayPo = new DailyListPO();
        todayPo.setDailyType(1);
        todayPo.setStatus(po.getStatus());
        todayPo.setWorkerId(po.getWorkerId());
        List<DailyListVO> todayList = this.baseMapper.dailyList(page, todayPo).getRecords();
        po.setDailyType(2);
        List<DailyListVO> historyDailyList = this.baseMapper.dailyList(page, po).getRecords();
        MiniDailyListVO vo = new MiniDailyListVO();
        vo.setTodayDaily(todayList);
        vo.setHistoryDailyList(historyDailyList);
        return new ApiResponse<>(vo);
    }

    @Override
    public List<DailyListExcelVO> dailyDownList(DailyListPO po) {
        LocalDate now = LocalDate.now();
        List<SysDaily> dailyList = list(new LambdaQueryWrapper<SysDaily>()
                .between(po.getDailyTimeStart() != null && po.getDailyTimeEnd() != null,
                        SysDaily::getDailyTime, po.getDailyTimeStart(), po.getDailyTimeEnd())
                .eq(po.getStatus() != null, SysDaily::getStatus, po.getStatus())
                .eq(po.getWorkerId() != null, SysDaily::getWorkerId, po.getWorkerId())
                .le(SysDaily::getDailyTime, now)
                .ne(SysDaily::getState, 2)
                .orderByDesc(SysDaily::getDailyTime));
        Set<Long> dailyIds = dailyList.stream().map(SysDaily::getId).collect(Collectors.toSet());
        return sysDailyMapper.downListByDailyIds(dailyIds);
    }

    @Override
    public ApiResponse<DailyInfoVO> dailyInfo(DailyInfoPO po) {
        SysDaily sysDaily = null;
        if (po.getDailyId() != null) {
            sysDaily = getById(po.getDailyId());
        }
        if (sysDaily == null) {
            return new ApiResponse<>();
        }
        List<DailySingleListVO> singleList = dailySingleList(sysDaily.getId());
        DailyInfoVO infoVO = BeanUtil.beanA2beanB(sysDaily, DailyInfoVO.class);
        infoVO.setSingleList(singleList);
        if (DailyShiroUtil.isBigLead() || DailyShiroUtil.isAssistant()) {
            updateById(sysDaily.setIsRead(true));
        }
        Boolean notMy = !sysDaily.getWorkerId().equals(ShiroUtil.getUserId());
        Boolean canGive = sysFlowerMapper.selectCount(new LambdaQueryWrapper<SysFlower>()
                .eq(SysFlower::getUserId, ShiroUtil.getUserId())
                .eq(SysFlower::getGiveDate, LocalDate.now())
        ) < SysConfigEnum.GIVE_FLOWER_MAX_TIMES.getValue();
        infoVO
                .setWorkerName(sysUserService.getById(infoVO.getWorkerId()).getRealName())
                .setCanGiveFlower(notMy && canGive);
        return new ApiResponse<>(infoVO);
    }

    @Override
    public ApiResponse<DailyInfoVO> dailyToday() {
        SysDaily sysDaily = getOne(
                new LambdaQueryWrapper<SysDaily>()
                        .eq(SysDaily::getWorkerId, ShiroUtil.getUserId())
                        .eq(SysDaily::getDailyTime, LocalDate.now())
        );
        if (sysDaily == null) {
            return new ApiResponse<>();
        }
        List<DailySingleListVO> singleList = dailySingleList(sysDaily.getId());
        DailyInfoVO infoVO = BeanUtil.beanA2beanB(sysDaily, DailyInfoVO.class);
        infoVO.setSingleList(singleList);
        return new ApiResponse<>(infoVO);
    }

    @Override
    public ApiResponse<DailyInfoVO> dailyPlan(DailyListPO po) {
        Long userId;
        if (po.getWorkerId() == null) {
            userId = ShiroUtil.getUserId();
        }else {
            userId = po.getWorkerId();
        }
        SysDaily sysDaily = getOne(
                new LambdaQueryWrapper<SysDaily>()
                        .eq(SysDaily::getWorkerId, userId)
                        .eq(SysDaily::getState, 2)
                        .gt(SysDaily::getDailyTime, LocalDate.now())
        );
        if (sysDaily == null) {
            return new ApiResponse<>();
        }
        List<DailySingleListVO> singleList = dailySingleList(sysDaily.getId());
        DailyInfoVO infoVO = BeanUtil.beanA2beanB(sysDaily, DailyInfoVO.class);
        infoVO.setSingleList(singleList);
        return new ApiResponse<>(infoVO);
    }

    @Override
    public List<DailySingleListVO> dailySingleList(Long dailyId) {
        List<SysDailySingle> list = sysDailySingleService.list(new LambdaQueryWrapper<SysDailySingle>()
                .eq(SysDailySingle::getDailyId, dailyId));
        return BeanUtil.listA2ListB(list, DailySingleListVO.class);
    }

    @Override
    public ApiResponse<DailySingleListVO> dailySingleList(DailySingleListPO po) {
        return new ApiResponse<>(dailySingleList(po.getDailyId()));
    }

    @Override
    public ApiResponse<String> dailyUpdate(DailyUpdatePO po) {
        LocalDate now = LocalDate.now();
        if (po.getDailyAdd() == null || po.getDailyId() == null) {
            throw new BusException("某添加条件为空!");
        }
        if (po.getDailyAdd().getDailyTime().isBefore(now)) {
            throw new BusException("非修改时间!");
        }
        SysDaily sysDaily = getById(po.getDailyId());
        if (sysDaily.getDailyTime().isEqual(now)) {
            sysDaily
                    .setState(0);
        }
        if (Objects.equals(sysDaily.getState(), 2)) {
            if (po.getDailyAdd().getDailyTime().isAfter(LocalDate.now())) {
                sysDaily.setDailyTime(po.getDailyAdd().getDailyTime());
            }
        }
        sysDailySingleService.remove(new LambdaQueryWrapper<SysDailySingle>().eq(SysDailySingle::getDailyId, sysDaily.getId()));
        sysDaily.setInsertTime(LocalDateTime.now());
        updateById(sysDaily.setSummary(po.getDailyAdd().getSummary()));
        List<SysDailySingle> collect = po.getDailyAdd().getSingleList().stream().peek(k -> k.setDailyId(sysDaily.getId())).collect(Collectors.toList());
        sysDailySingleService.saveOrUpdateBatch(collect);
        return new ApiResponse<>("修改成功！");
    }

    @Override
    public ApiResponse<Void> dailyStatusUpdate(DailyStatusUpdatePO po) {
        SysDaily sysDaily = getById(po.getDailyId());
        sysDaily.setStatus(po.getStatus());
        updateById(sysDaily);
        return new ApiResponse<>();
    }

    @Override
    public ApiResponse<DailyUserListVO> dailyUserList(DailyUserListPO po) {
        LocalDate now = LocalDate.now();
        List<UserListVO> userList = sysUserMapper.userListByDept(po.getDeptId());
        List<DailyUserListVO> dailyUserListVOS = BeanUtil.listA2ListB(userList, DailyUserListVO.class);
        Set<Long> dailyUserIds = dailyUserListVOS.stream().map(DailyUserListVO::getUserId).collect(Collectors.toSet());
        Set<Long> submitUserIds = list(
                new LambdaQueryWrapper<SysDaily>()
                        .ne(SysDaily::getState, 2)
                        .in(SysDaily::getWorkerId, dailyUserIds)
                        .eq(SysDaily::getDailyTime, now))
                .stream()
                .map(SysDaily::getWorkerId)
                .collect(Collectors.toSet());
        Set<Long> noReadUserIds = list(
                new LambdaQueryWrapper<SysDaily>()
                        .ne(SysDaily::getState, 2)
                        .in(SysDaily::getWorkerId, dailyUserIds)
                        .eq(SysDaily::getIsRead, false))
                .stream()
                .map(SysDaily::getWorkerId)
                .collect(Collectors.toSet());
        for (DailyUserListVO dailyUserListVO : dailyUserListVOS) {
            dailyUserListVO
                    .setIsSubmit(submitUserIds.contains(dailyUserListVO.getUserId()))
                    .setIsRead(!noReadUserIds.contains(dailyUserListVO.getUserId()));
        }
        return new ApiResponse<>(dailyUserListVOS);
    }
}
